package com.ruoyi.common.utils.poi;

import com.ruoyi.common.exception.global.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class MyExcelUtils {
    // 生成excel
    public static void generateExcel(HttpServletResponse response, List<LinkedHashMap<String, Object>> data, String filePrefixName, List<String> pictureColumnName) {
        response.setContentType("application/x-excel");
        String fileName = filePrefixName + "(" + OffsetDateTime.now().format(DateTimeFormatter.ofPattern("MM-dd")) + ").xlsx";
        String encodedFileName = null;
        try {
            encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new CustomException("excel处理文件名称出错");
        }
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
        Workbook workbook = null;
        if (ObjectUtils.isEmpty(pictureColumnName)) {
            workbook = getWorkbook(data);
        } else {
            workbook = getWorkbook(data, pictureColumnName);
        }

        try {
            workbook.write(response.getOutputStream());
            workbook.close();
        } catch (IOException e) {
            log.error("导出Excel失败", e);
            throw new CustomException("导出Excel失败");
        }
    }

    public static Workbook getWorkbook(List<LinkedHashMap<String, Object>> data) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("报表");

        CellStyle textCellStyle = workbook.createCellStyle();
        DataFormat format = workbook.createDataFormat();
        textCellStyle.setDataFormat(format.getFormat("@"));

        // 创建标题行
        Row headerRow = sheet.createRow(0);
        int colNum = 0;
        for (String key : data.get(0).keySet()) {
            Cell cell = headerRow.createCell(colNum++);
            cell.setCellValue(key);
        }

        // 填充数据行
        int rowNum = 1;
        for (Map<String, Object> rowData : data) {
            Row row = sheet.createRow(rowNum++);
            colNum = 0;

            for (Object value : rowData.values()) {
                Cell cell = row.createCell(colNum++);

                if (value != null) {
                    if (value instanceof Number) {
                        if (value instanceof Long || value instanceof Integer) {
                            cell.setCellStyle(textCellStyle);
                            cell.setCellValue(value.toString());
                        } else {
                            cell.setCellValue(((Number) value).doubleValue());
                        }
                    } else if (value instanceof Boolean) {
                        cell.setCellValue((Boolean) value);
                    } else {
                        cell.setCellValue(value.toString());
                    }
                } else {
                    cell.setCellValue("");
                }
            }
        }
        return workbook;
    }

    public static Workbook getWorkbook(List<LinkedHashMap<String, Object>> data, List<String> pictureColumnName) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("报表");

        // 单元格样式：文本格式
        CellStyle textCellStyle = workbook.createCellStyle();
        DataFormat format = workbook.createDataFormat();
        textCellStyle.setDataFormat(format.getFormat("@"));

        // ====== 创建标题行 ======
        Row headerRow = sheet.createRow(0);
        List<String> headers = new ArrayList<>(data.get(0).keySet());
        for (int i = 0; i < headers.size(); i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers.get(i));
        }

        handlePicNew(data, pictureColumnName, sheet, headers, workbook, textCellStyle);

        // ====== 自动列宽 ======
        for (int i = 0; i < headers.size(); i++) {
            sheet.autoSizeColumn(i);
            // 限制最大宽度
            if (sheet.getColumnWidth(i) > 255 * 256) {
                sheet.setColumnWidth(i, 255 * 256);
            }
        }

        return workbook;
    }

    private static void handlePic(List<LinkedHashMap<String, Object>> data, List<String> pictureColumnName, Sheet sheet, List<String> headers, Workbook workbook, CellStyle textCellStyle) {
        // ====== 填充数据行 + 插入图片 ======
        int rowNum = 1;
        XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch(); // 所有图片共用一个绘图对象

        for (Map<String, Object> rowData : data) {
            Row row = sheet.createRow(rowNum);

            // 设置行高（可选：根据图片调整）
            row.setHeightInPoints(80); // 初始高度，适配横向排列

            int colNum = 0;
            for (String key : headers) {
                Cell cell = row.createCell(colNum);
                Object value = rowData.get(key);

                // 检查是否是图片列
                if (pictureColumnName.contains(key) && value != null && !value.toString().trim().isEmpty()) {
                    String urlsStr = value.toString().trim();
                    String[] urlArray = urlsStr.split(",");

                    // 列宽按图片数量动态扩展，便于横向排布
                    int imgWidthPx = 60; // 每张图片宽度(px)
                    int imgHeightPx = 60; // 每张图片高度(px)
                    int gapPx = 4; // 图片之间的间距(px)
                    int expectedWidthUnits = (int) (((urlArray.length * (imgWidthPx + gapPx)) + 10) / 7.0 * 256);
                    int newWidth = Math.min(255 * 256, Math.max(sheet.getColumnWidth(colNum), expectedWidthUnits));
                    sheet.setColumnWidth(colNum, newWidth);
                    row.setHeightInPoints(Math.max(row.getHeightInPoints(), (float) (imgHeightPx * 0.75 + 8)));

                    // 为每张图创建一个锚点，依次插入（横向并排）
                    for (int i = 0; i < urlArray.length; i++) {
                        String imgURL = urlArray[i].trim();
                        if (imgURL.isEmpty()) continue;

                        try {
                            byte[] imageBytes = downloadImage(imgURL);
                            if (imageBytes != null && imageBytes.length > 0) {
                                // 根据字节自动识别图片类型（PNG/JPEG/GIF）
                                int pictureIdx = workbook.addPicture(imageBytes, detectPictureType(imageBytes));

                                // 创建锚点（定位图片位置：同一列内横向偏移）
                                XSSFClientAnchor anchor = new XSSFClientAnchor();
                                anchor.setCol1(colNum);           // 起始列
                                anchor.setRow1(rowNum);           // 起始行
                                anchor.setCol2(colNum + 1);       // 结束列（占用当前列区域）
                                anchor.setRow2(rowNum + 1);       // 结束行（占用当前行高度）
                                anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);

                                // 设置图片横向偏移，让多图并排
                                int xOffset = i * (imgWidthPx + gapPx);
                                anchor.setDx1(pxToEMU(xOffset));
                                anchor.setDx2(pxToEMU(xOffset + imgWidthPx));
                                // 纵向贴着上边：高度按固定值
                                anchor.setDy1(pxToEMU(0));
                                anchor.setDy2(pxToEMU(imgHeightPx));

                                drawing.createPicture(anchor, pictureIdx);

                                // 动态调整行高（每多一张图增加高度）
                                if (i > 0) {
                                    row.setHeightInPoints((short) (100 + i * 80));
                                }
                            }
                        } catch (Exception e) {
                            System.err.println("Failed to insert image: " + imgURL);
                            e.printStackTrace();
                        }
                    }

                    // 图片列不再输出URL文本
                    cell.setCellValue("");
                } else {
                    // 普通字段处理
                    if (value != null) {
                        if (value instanceof Number) {
                            if (value instanceof Long || value instanceof Integer) {
                                cell.setCellStyle(textCellStyle);
                                cell.setCellValue(value.toString());
                            } else {
                                cell.setCellValue(((Number) value).doubleValue());
                            }
                        } else if (value instanceof Boolean) {
                            cell.setCellValue((Boolean) value);
                        } else {
                            cell.setCellValue(value.toString());
                        }
                    } else {
                        cell.setCellValue("");
                    }
                }

                colNum++;
            }

            rowNum++;
        }
    }

    private static void handlePicNew(List<LinkedHashMap<String, Object>> data, List<String> pictureColumnName, Sheet sheet, List<String> headers, Workbook workbook, CellStyle textCellStyle) {
        // ====== 填充数据行 + 插入图片 ======
        int rowNum = 1;
        XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch(); // 所有图片共用一个绘图对象
        for (Map<String, Object> rowData : data) {
            Row row = sheet.createRow(rowNum);

            int colNum = 0;
            for (String key : headers) {
                Cell cell = row.createCell(colNum);
                Object value = rowData.get(key);

                if (pictureColumnName.contains(key) && value != null && !value.toString().trim().isEmpty()) {
                    String urlsStr = value.toString().trim();
                    String[] urlArray = urlsStr.split(",");

                    // 如果有多个图片链接，则进行拼接处理
                    if (urlArray.length > 1) {
                        try {
                            // 调用拼接图片逻辑（此处需根据实际情况调整）
                            BufferedImage concatenatedImage = ImageConcatenation.concatenateImages(urlArray); // 假设有一个静态方法可以调用
                            byte[] imageBytes = convertBufferedImageToByteArray(concatenatedImage, "PNG"); // 将BufferedImage转换为byte数组

                            int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
                            XSSFDrawing drawingNew = (XSSFDrawing) sheet.createDrawingPatriarch();

                            XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, colNum, rowNum, colNum + 1, rowNum + 1);
                            anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);

                            drawingNew.createPicture(anchor, pictureIdx);

                            // 动态设置列宽和行高以适应新图片大小
//                            sheet.setColumnWidth(colNum, Math.min(255 * 256, concatenatedImage.getWidth() * 30)); // 简单计算宽度单位
//                            row.setHeightInPoints(concatenatedImage.getHeight() * 0.75f); // 粗略计算高度

                        } catch (Exception e) {
                            System.err.println("Failed to concatenate or insert images: " + urlsStr);
                            e.printStackTrace();
                        }
                    } else {
                        // 普通字段处理
                        if (value != null) {
                            if (value instanceof Number) {
                                if (value instanceof Long || value instanceof Integer) {
                                    cell.setCellStyle(textCellStyle);
                                    cell.setCellValue(value.toString());
                                } else {
                                    cell.setCellValue(((Number) value).doubleValue());
                                }
                            } else if (value instanceof Boolean) {
                                cell.setCellValue((Boolean) value);
                            } else {
                                cell.setCellValue(value.toString());
                            }
                        } else {
                            cell.setCellValue("");
                        }

                    }

                    cell.setCellValue(""); // 清空该单元格内容，仅显示图片
                } else {
                    // 普通字段处理
                    // ...
                }

                colNum++;
            }

            rowNum++;
        }
    }


    // 新增方法：将BufferedImage转换为字节数组
    private static byte[] convertBufferedImageToByteArray(BufferedImage image, String formatName) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, formatName, baos);
        return baos.toByteArray();
    }

    /**
     * 下载图片并返回字节数组
     */
    private static byte[] downloadImage(String imageUrl) {
        trustAllHosts();
        try {
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
            connection.setDoInput(true);

            // 设置 User-Agent 防止被拒绝
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");

            if (connection.getResponseCode() != 200) {
                System.err.println("Image download failed: " + imageUrl + " | Code: " + connection.getResponseCode());
                return null;
            }

            ByteArrayOutputStream output = new ByteArrayOutputStream();
            try (InputStream input = connection.getInputStream()) {
                byte[] buffer = new byte[4096];
                int n;
                while ((n = input.read(buffer)) != -1) {
                    output.write(buffer, 0, n);
                }
            }
            return output.toByteArray();
        } catch (Exception e) {
            System.err.println("Error downloading image: " + imageUrl);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据图片字节内容识别类型，返回POI图片类型常量
     */
    private static int detectPictureType(byte[] bytes) {
        if (bytes == null || bytes.length < 8) {
            return Workbook.PICTURE_TYPE_PNG;
        }
        // PNG: 89 50 4E 47 0D 0A 1A 0A
        if ((bytes[0] & 0xFF) == 0x89 && (bytes[1] & 0xFF) == 0x50 && (bytes[2] & 0xFF) == 0x4E && (bytes[3] & 0xFF) == 0x47) {
            return Workbook.PICTURE_TYPE_PNG;
        }
        // JPEG: FF D8 ... FF
        if ((bytes[0] & 0xFF) == 0xFF && (bytes[1] & 0xFF) == 0xD8) {
            return Workbook.PICTURE_TYPE_JPEG;
        }
        // GIF: GIF87a / GIF89a
        if (bytes.length >= 6 && bytes[0] == 'G' && bytes[1] == 'I' && bytes[2] == 'F' && bytes[3] == '8' && (bytes[4] == '7' || bytes[4] == '9') && bytes[5] == 'a') {
            return Workbook.PICTURE_TYPE_PNG;
        }
        // 默认用PNG
        return Workbook.PICTURE_TYPE_PNG;
    }

    /**
     * 将任意实体对象列表转换为 LinkedHashMap 列表
     * key: 字段名, value: 字段值
     */
    public static <T> List<LinkedHashMap<String, Object>> convertToMapList(List<T> dataList) {
        List<LinkedHashMap<String, Object>> result = new ArrayList<>();

        if (dataList == null || dataList.isEmpty()) {
            return result; // 空列表处理
        }

        Class<?> clazz = dataList.get(0).getClass(); // 获取类型信息
        Field[] fields = clazz.getDeclaredFields();

        for (T item : dataList) {
            LinkedHashMap<String, Object> map = new LinkedHashMap<>();
            for (Field field : fields) {
                field.setAccessible(true); // 允许访问 private 字段
                try {
                    Object value = field.get(item);
                    map.put(field.getName(), value);
                } catch (IllegalAccessException e) {
                    map.put(field.getName(), null);
                }
            }
            result.add(map);
        }

        return result;
    }

    // px转EMU（POI锚点偏移单位）
    private static int pxToEMU(int px) {
        return px * 9525;
    }

    // 忽略https的签名
    public static void trustAllHosts() {
        try {
            javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[]{
                    new javax.net.ssl.X509TrustManager() {
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
                        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { }
                        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { }
                    }
            };

            javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
